gin的router不是很方便,我們定義的接口只能寫成以下形式,之後再靠自己來處理參數
解釋:
正式來寫gin吧!
在app中創建router package,用來解析路由,在裡面創建main.go,接著創建serve package,用來放最後處理的function
在router中創建main.go寫入
package router
import (
"app/setting"
"app/serve"
"github.com/gin-gonic/gin"
)
func MainRouter() *gin.Engine {
r := gin.New()
gin.SetMode(setting.Servers["main"].RunMode)
/*home page*/
r.GET("/", serve.GetRoot)
/*owner*/
r.GET("/:owner", serve.GetOwner)
/*works*/
r.GET("/:owner/*project", serve.GetProject)
/*auth*/
owner := r.Group("/:owner")
{
work := owner.Group("/*work")
{
work.POST("", serve.CreateBlog)
work.PUT("", serve.UpdateBlog)
work.DELETE("", serve.DelBlog)
}
}
return r
}
基本的router,post, put, delete等操作需要登錄驗證,之後需要寫middleware來處理。
在serve中創建main.go,寫個雛型
package serve
import (
"github.com/gin-gonic/gin"
"net/http"
"strings"
)
/*home page*/
// get root
func GetRoot(c *gin.Context) {
}
/*owner*/
func GetOwner(c *gin.Context) {
}
/*project*/
func GetBlog(c *gin.Context) {
projs, blog := splitProject(c.Param("project"))
c.JSON(http.StatusOK, gin.H{
"owner" : c.Param("owner"),
"project" : projs,
"blog" : blog,
})
}
func PostProject(c *gin.Context){
}
func PutProject(c *gin.Context){
}
func DelProject(c *gin.Context){
}
// split url to slice of projects and last project or blog
func splitWork(url string) ([]string, string) {
works := strings.Split(url, "/")
return works[:len(works)-1], works[len(works)-1]
}
解釋:
寫個test
創建main_test.go,寫入
package serve
import (
"testing"
)
func TestServe_SplitWork(t *testing.T) {
type expect struct {
project []string
blog string
}
// build test table
var splitTest = []struct {
url string // input
expect_ expect // expected result
}{
{"/foo", expect{[]string{""}, "foo"}},
{"/foo/bar", expect{[]string{"", "foo"}, "bar"}},
{"/foo/bar/blog", expect{[]string{"", "foo", "bar"}, "blog"}},
}
for _, value := range splitTest {
proj, blog := splitWork(value.url)
for i, v := range proj {
if v != value.expect_.project[i] {
t.Errorf("splitWork(%s).project[%d] = %s; expected %s\n", value.url, i, v, value.expect_.project[i])
}
}
// test blog
if blog != value.expect_.blog {
t.Errorf("splitWork(%s).blog = %s; expected %s\n", value.url, blog, value.expect_.blog)
}
}
}
解釋:
跑一下結果
go test ./serve
ok app/serve 0.005s
我們的路由已經註冊完了,沒辦法定義其他服務(使用者登入,載入js, css檔等等...),解決辦法有兩種
這邊我選擇使用subdomain,但是gin本身也不支援,所以必須從ServeHTTP下手。
在router中創建host_switch.go,寫代碼之前,以下是我參考的資料
寫入
package router
import (
"net/http"
"net/url"
)
// We need an object that implements the http.Handler interface.
// Therefore we need a type for which we implement the ServeHTTP method.
// We just use a map here, in which we map host names (with port) to http.Handlers
type HostSwitch map[string]http.Handler
// Implement the ServeHTTP method on our new type
func (hs HostSwitch) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Check if a http.Handler is registered for the given host.
// If yes, use it to handle the request.
if handler := hs[r.Host]; handler != nil {
handler.ServeHTTP(w, r)
} else {
// Handle host names for which no handler is registered
http.Error(w, "Forbidden", 403) // Or Redirect?
}
}
在main.go寫入
package main
import (
"app/router"
"app/setting"
"fmt"
"log"
"net/http"
)
var hs router.HostSwitch
func main() {
mainRouter := router.MainRouter()
// Make a new HostSwitch and insert the router (our http handler)
hs = make(router.HostSwitch)
hs[fmt.Sprintf("%s:%d", setting.Servers["main"].Host, setting.Servers["main"].Port)] = mainRouter
s := &http.Server{
Addr: fmt.Sprintf(":%d", setting.Servers["main"].Port),
Handler: hs,
ReadTimeout: setting.Servers["main"].ReadTimeout,
WriteTimeout: setting.Servers["main"].WriteTimeout,
}
log.Fatal(s.ListenAndServe())
}
解釋:
現在應該能跑起來了
輸入
go run main.go
目前的工作環境
.
├── app
│ ├── config
│ │ └── app
│ │ └── app.yaml
│ ├── go.mod
│ ├── go.sum
│ ├── main.go
│ ├── router
│ │ ├── host_switch.go
│ │ └── main.go
│ ├── serve
│ │ ├── main.go
│ │ └── main_test.go
│ └── setting
│ └── setting.go
└── database
題外話,想要在local host玩玩subdomain可以看這篇
你有些go打錯成gin了
抱歉,我搜了一下沒發現,應該都是要說gin沒錯,可能是我的表達能力不好
喔喔 不好意思 我誤會了